﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;   //   for Texture2D
using Microsoft.Xna.Framework;  //  for Vector2
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace RisingThreat
{
    class Camera
    {
        public Vector3 camDir;
        public Vector3 camNorm;
        public Vector3 lookAt;
        public Vector3 position;
        public Matrix cameraProjectionMatrix;
        public Matrix cameraViewMatrix;
        public BoundingSphere bounding;
        public GraphicsDeviceManager graphics;
        private float cameraAngle = -15.0f;
        private float cameraDistance = 2.0f;
        float testfloat;
        float test2float;

        public Camera(GraphicsDeviceManager graphs)
        {
            bounding = new BoundingSphere(Vector3.Zero, 1.0f);
            graphics = graphs;
        }

        public void InitCamera(Player p)
        {
            //calculate camera position and lookat
            Vector3 dir = new Vector3((float)(Math.Cos(-p.steer.orientation)), 0.0f, (float)(Math.Sin(-p.steer.orientation)));// player.facing;
            Vector3 axis = Vector3.Cross(Vector3.Up, dir);
            axis.Normalize();
            Quaternion quat = Quaternion.CreateFromAxisAngle(axis, MathHelper.ToRadians(cameraAngle));
            camDir = Vector3.Transform(dir, quat);
            camDir.Normalize();
            camNorm = Vector3.Cross(camDir, Vector3.Up);
            lookAt = p.steer.position - camDir * 1;
            position = p.steer.position + camDir * cameraDistance;// cameraDistance;// +new Vector3(0.0f, 5.0f, 0.0f);
            bounding.Center = position;

            //Camera view matrix
            cameraViewMatrix = Matrix.CreateLookAt(
                position,
                lookAt,
                Vector3.Up);

            //Camera Projection Matrix
            cameraProjectionMatrix = Matrix.CreatePerspectiveFieldOfView(
                MathHelper.ToRadians(45.0f),
                graphics.GraphicsDevice.Viewport.AspectRatio,
                0.1f,
                100.0f);
        }

        public void UpdateCamera(Player p, Level level)
        {
            //calculate camera position and lookat
            Vector3 dir = new Vector3((float)(Math.Cos(-p.steer.orientation)), 0.0f, (float)(Math.Sin(-p.steer.orientation)));// player.facing;
            Vector3 axis = Vector3.Cross(Vector3.Up, dir);
            axis.Normalize();
            Quaternion quat = Quaternion.CreateFromAxisAngle(axis, MathHelper.ToRadians(cameraAngle));
            camDir = Vector3.Transform(dir, quat);
            camDir.Normalize();
            camNorm = Vector3.Cross(camDir, Vector3.Up);
            lookAt = p.steer.position - camDir * 1;
            position = p.steer.position + camDir * cameraDistance;// cameraDistance;// +new Vector3(0.0f, 5.0f, 0.0f);
            bounding.Center = position;
            //clamp to my fake "wall", if there was collision detection you'd do that here instead.
            //camera.position.Z = MathHelper.Clamp(camera.position.Z, -10000.0f, 38.0f);

            //if (coolcamera)
           //     camera.CheckForCollisions(levelBVH);



            test2float = bounding.Center.Y;
            CheckForCollisions(level);
            testfloat = (position - p.steer.position).Length();

            position.Y = MathHelper.Lerp(3.0f, 2.0f, (position - p.steer.position).Length() / cameraDistance);
            
            //Camera view matrix
            cameraViewMatrix = Matrix.CreateLookAt(
                position,
                lookAt,
                Vector3.Up);

            //Camera Projection Matrix
            cameraProjectionMatrix = Matrix.CreatePerspectiveFieldOfView(
                MathHelper.ToRadians(45.0f),
                graphics.GraphicsDevice.Viewport.AspectRatio,
                0.1f,
                150.0f);
        }

        public void CheckForCollisions(Level level)
        {
            CollisionDetector cd = new CollisionDetector();
            HashSet<QuadTreeItem> hashie = level.getPotentialCollisions(bounding);

            List<QuadTreeItem> collisions = cd.detectLevelCollisions(bounding, hashie);
            foreach (QuadTreeItem item in collisions)
            {

                if (bounding.Intersects(item.getBoundingVolume()))
                {
                    ResolveCollisionBVH(item);
                }
            }
        }

        public void ResolveCollisionBVH(QuadTreeItem item)
        {
            BoundingBox itemBound = new BoundingBox(item.getBoundingVolume().Min, item.getBoundingVolume().Max);
            Vector3 itemBoundCenter = new Vector3((itemBound.Min.X + itemBound.Max.X) / 2, 1.5f, (itemBound.Min.Z + itemBound.Max.Z) / 2);

            if ((this.position.X > (itemBound.Min.X - this.bounding.Radius / 2)) && this.position.X < (itemBound.Max.X + this.bounding.Radius / 2))
            {
                if (this.position.Z > itemBoundCenter.Z)
                {
                    this.position.Z = (itemBound.Max.Z + this.bounding.Radius);
                }
                else
                {
                    this.position.Z = (itemBound.Min.Z - this.bounding.Radius);
                }
            }
            else
            {
                if (this.position.X > itemBoundCenter.X)
                {
                    this.position.X = (itemBound.Max.X + this.bounding.Radius);
                }
                else
                {
                    this.position.X = (itemBound.Min.X - this.bounding.Radius);
                }
            }
        }
    }
}
